---
title: 添加 RSS 摘要
description: 通过向你的 Astro 网站添加 RSS 摘要让用户来订阅你的内容。
i18nReady: true
type: recipe
---
import Since from '~/components/Since.astro';
import { Steps } from '@astrojs/starlight/components';
import ReadMore from '~/components/ReadMore.astro';
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro';

Astro 支持为博客和其他内容网站快速，自动的 RSS 提要生成。RSS 源为用户提供了一种订阅内容的简单方法。

## 设置 `@astrojs/rss`

[`@astrojs/rss` 包](https://github.com/withastro/astro/tree/main/packages/astro-rss) 提供了使用 [API 端点](/zh-cn/guides/endpoints/#静态文件端点) 生成 RSS 摘要的帮助程序。这使得静态构建和使用 [SSR 适配器](/zh-cn/guides/on-demand-rendering/) 时的按需生成都成为可能。

<Steps>
1. 使用你喜欢的包管理器安装 `@astrojs/rss`：

    <PackageManagerTabs>
      <Fragment slot="npm">
      ```shell
      npm install @astrojs/rss
      ```
      </Fragment>
      <Fragment slot="pnpm">
      ```shell
      pnpm add @astrojs/rss
      ```
      </Fragment>
      <Fragment slot="yarn">
      ```shell
      yarn add @astrojs/rss
      ```
      </Fragment>
    </PackageManagerTabs>

    :::tip
    确保已在项目的 `astro.config` 中[配置了 `site`](/zh-cn/reference/configuration-reference/#site)。这将用于生成指向你的 RSS 文章的链接。
    :::

2. 在 `src/pages/` 中创建一个文件，其中包含你选择的名称和扩展名 `.xml.js`，以用作 Feed 的输出 URL。一些常见的 RSS 源 URL 名称是 `feed.xml` 或 `rss.xml`。

    下面的示例文件 `src/pages/rss.xml.js` 将在 `site/rss.xml` 上创建一个 RSS 提要。

3. 将 `rss()` 帮助程序从 `@astrojs/rss` 包导入到你的 `.xml.js` 文件中，并导出一个使用以下参数返回它的函数：

    ```js title="src/pages/rss.xml.js"
    import rss from '@astrojs/rss';

    export function GET(context) {
      return rss({
        // 输出的 xml 中的`<title>`字段
        title: 'Buzz’s Blog',
        // 输出的 xml 中的`<description>`字段
        description: 'A humble Astronaut’s guide to the stars',
        // 从端点上下文获取项目“site”
        // https://docs.astro.build/zh-cn/reference/api-reference/#site
        site: context.site,
        // 输出的 xml 中的`<item>`数组
        // 有关使用内容集合和 glob 导入的示例，请参阅“生成`items`”部分
        items: [],
        // (可选) 注入自定义 xml
        customData: `<language>en-us</language>`,
      });
    }
    ```
</Steps>

<ReadMore>请参阅 [`@astrojs/rss` README](https://github.com/withastro/astro/tree/main/packages/astro-rss) 以获取完整的配置参考。</ReadMore>

## 生成 `items`

`items` 字段接受 RSS 摘要对象列表，这些对象可以使用 `getCollection()` 从内容集合条目生成，或者使用 `pagesGlobToRssItems()` 从页面文件生成。

RSS 源标准格式包括每个已发布项目的元数据，包括以下值：

- `title`: 条目的标题。只有在设置了 `description` 时才是可选的，否则是必需的。
- `description`: 条目的简短摘录或描述。只有在设置了 `title` 时才是可选的，否则是必需的。
- `link`: 指向条目原始来源的 URL。（可选）
- `pubDate`: 条目发布日期。（可选）
- `content`: 你的帖子的全部内容。（可选）

<ReadMore>请参阅 [`items` 配置参考](https://github.com/withastro/astro/tree/main/packages/astro-rss#items) 以获取完整的选项列表。</ReadMore>

### 使用内容集合

要创建由[内容集合](/zh-cn/guides/content-collections/)管理的页面 RSS 摘要，可以使用 `getCollection()` 函数来获取 `items` 数组所需的数据。你需要从返回的数据中指定每个所需属性（例如 `title`，`description`）的值。

```js title="src/pages/rss.xml.js" "items:" "const blog = await getCollection('blog');"
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';

export async function GET(context) {
  const blog = await getCollection('blog');
  return rss({
    title: 'Buzz’s Blog',
    description: 'A humble Astronaut’s guide to the stars',
    site: context.site,
    items: blog.map((post) => ({
      title: post.data.title,
      pubDate: post.data.pubDate,
      description: post.data.description,
      // 从 `id` 属性计算出 RSS 链接
      // 这个例子假设所有的文章都被渲染为 `/blog/[id]` 路由
      link: `/blog/${post.id}/`,
    })),
  });
}
```

可选：替换现有的博客集合架构以强制实施预期的 RSS 属性。

若要确保每个博客条目生成有效的 RSS 源项，可以选择导入并应用 `rssSchema`，而不是定义架构的每个单独属性。

```js title="src/content.config.ts" "rssSchema"
import { defineCollection } from 'astro:content';
import { rssSchema } from '@astrojs/rss';

const blog = defineCollection({
  schema: rssSchema,
});

export const collections = { blog };
```

## 使用 glob 导入

<p><Since v="2.1.0" pkg="@astrojs/rss" /></p>

要从 `src/pages/` 中的文档创建 RSS 摘要，请使用 `pagesGlobToRssItems()` 帮助程序。它接受一个 [`import.meta.glob`](https://cn.vite.dev/guide/features.html#glob-import) 结果并输出一个有效 RSS 摘要项数组（请参阅[有关编写 glob 模式的更多信息](/zh-cn/guides/imports/#glob-模式) 以指定要包含哪些页面）。

:::caution
此函数假定但不验证每个文档的 frontmatter 中都存在所有必需的 feed 属性。如果遇到错误，请手动验证每个页面的 frontmatter。
:::

```js title="src/pages/rss.xml.js" "pagesGlobToRssItems" "await pagesGlobToRssItems("
import rss, { pagesGlobToRssItems } from '@astrojs/rss';

export async function GET(context) {
  return rss({
    title: 'Buzz’s Blog',
    description: 'A humble Astronaut’s guide to the stars',
    site: context.site,
    items: await pagesGlobToRssItems(
      import.meta.glob('./blog/*.{md,mdx}'),
    ),
  });
}
```

:::note[使用旧版本？]

在 `@astrojs/rss` 的旧版本中，直接将 glob 结果传递给 `items`，而不是使用 `pagesGlobToRssItems()` 包装器：
```js
items: import.meta.glob('./blog/*.{md,mdx}'),
```
此方法自 Astro v2.1.0 起已被弃用，不能在现代项目中使用。
:::


### 包含完整的文章内容

<p><Since v="1.6.14" /></p>

在 `rss.items` 上设置 `content` 键以提供文章的完整 HTML 内容。这允许 `@astrojs/rss` 将你的文章的完整 Markdown 文本提供给 RSS 阅读器。支持带有完整 URL 路径的图像和链接。但是，不支持使用相对路径的图片和指向其他页面的内部链接。

在渲染完整的文章内容时，你需要考虑图像、相对链接、样式、脚本以及文章中可能包含的超出标准 Markdown 文本的其他元素。 你可能需要在你的 `src/pages/rss.xml.js` 端点中加入额外的逻辑来处理这些元素，或者删除不需要的元素（例如，仅用于样式或网站交互的元素）。

你可以查看[这个具体的社区实现](https://github.com/delucis/astro-blog-full-text-rss/blob/latest/src/pages/rss.xml.ts)，它针对这些问题提出了解决方法，作为如何处理的示例。

:::tip
无论何时在 XML 中使用 HTML 内容，我们建议使用像 [`sanitize-html`](https://www.npmjs.com/package/sanitize-html) 这样的包，以确保你的内容被正确地清理、转义和编码。在这个过程中，这样的包可能也会移除一些无害的元素和属性，所以请确保验证输出并根据你的需要配置包。
:::

在使用内容集合时，使用标准的 Markdown 解析器如 [`markdown-it`](https://github.com/markdown-it/markdown-it) 渲染文章 `body` 并清理结果，包括渲染内容所需的任何额外标签（例如 `<img>`）：

```js title="src/pages/rss.xml.js" ins={3, 4, 5, 16}
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';
import sanitizeHtml from 'sanitize-html';
import MarkdownIt from 'markdown-it';
const parser = new MarkdownIt();

export async function GET(context) {
  const blog = await getCollection('blog');
  return rss({
    title: 'Buzz’s Blog',
    description: 'A humble Astronaut’s guide to the stars',
    site: context.site,
    items: blog.map((post) => ({
      link: `/blog/${post.id}/`,
      // 注意：这不会处理 MDX 文件中的组件或 JSX 表达式。
      content: sanitizeHtml(parser.render(post.body), {
        allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img'])
      }),
      ...post.data,
    })),
  });
}
```

当使用 glob 导入 Markdown 时，我们建议使用 `compiledContent()` 辅助函数来检索要进行清理的渲染 HTML。注意：此功能**不**支持 MDX 文件。

```js title="src/pages/rss.xml.js" ins={2, 13}
import rss from '@astrojs/rss';
import sanitizeHtml from 'sanitize-html';

export async function GET(context) {
  const postImportResult = import.meta.glob('../posts/**/*.md', { eager: true }); 
  const posts = Object.values(postImportResult);
  return rss({
    title: 'Buzz’s Blog',
    description: 'A humble Astronaut’s guide to the stars',
    site: context.site,
    items: await Promise.all(posts.map(async (post) => ({
      link: post.url,
      content: sanitizeHtml((await post.compiledContent())),
      ...post.frontmatter,
    }))),
  });
}
```

## 移除尾部斜杠

Astro 的 RSS 摘要默认生成带尾部斜杠的链接，无论你为 `trailingSlash` 配置了什么值。这意味着你的 RSS 链接可能与你的文章 url 不完全匹配。

如果你在 `astro.config.mjs` 中设置了 `trailingSlash: "never"`，请在 `rss()` 助手中设置 `trailingSlash: false`，以使你的摘要与项目配置相匹配。

```ts title="src/pages/rss.xml.js" ins={9}
import rss from '@astrojs/rss';

export function GET(context) {
  const posts = Object.values(postImportResult);
  return rss({
    title: 'Buzz 的博客',
    description: '一个谦逊的星际旅行宇航员向导',
    site: context.site,
    trailingSlash: false,
    items: posts.map((post) => ({
      link: post.url,
      ...post.frontmatter,
    })),
  });
}
```

## 添加样式表

你可以为 RSS 摘要添加样式表，以便在浏览器中查看文件时获得更好的用户体验。

使用 `rss` 函数的 `stylesheet` 选项指定到样式表的绝对路径。

```js
rss({
  // 例如，使用 "public/rss/styles.xsl" 中的样式表
  stylesheet: '/rss/styles.xsl',
  // ...
});
```

:::tip
如果你还没有 RSS 样式表的想法，我们建议你使用 [Pretty Feed v3 默认样式表](https://github.com/genmon/aboutfeeds/blob/main/tools/pretty-feed-v3.xsl)，你可以从 GitHub 上下载并将其保存到项目的 `public/` 目录中。
:::

## 开启自动发现 RSS 摘要

[RSS 自动发现](https://www.rssboard.org/rss-autodiscovery) 允许浏览器和其他软件自动从主 URL 找到网站的 RSS 摘要。
要启用此功能，请在你的网站的 `head` 元素中添加带有以下属性的 `<link>` 标签：

```jsx
<link
    rel="alternate"
    type="application/rss+xml"
    title="你的网站标题"
    href={new URL("rss.xml", Astro.site)}
/>
```

通过这个标签，你的博客读者可以将你的网站基础 URL 输入到他们的 RSS 阅读器中，订阅你的文章，而无需知道你的 RSS 摘要的具体 URL。

## 后续步骤

在浏览器中的 `your-domain.com/rss.xml` 访问你的提要并确认你可以看到每个文章的数据后，你现在可以[在你的网站上推广你的提要](https://medium.com/samsung-internet-dev/add-rss-feeds-to-your-website-to-keep-your-core-readers-engaged-3179dca9c91e#：~：text=com/~deno%2Drss-，Advertising%20your%20RSS%20feed，-Now%20you%20have)。将标准 RSS 图标添加到你的网站可以让你的读者知道他们可以在自己的提要阅读器中订阅你的文章。

## 资源

- [RSS Feeds](https://aboutfeeds.com/)
